package display.controller;

import java.awt.geom.Point2D;
import java.util.Iterator;

import prefuse.data.Tuple;
import prefuse.visual.EdgeItem;
import weeny.pre.util.Geom;
import display.WheelDisplay;
import display.structure.Wheel;

public class ForceWheelAnimator extends WheelSpeedAnimator{
	private long m_lasttime = -1;
	private double ratio = -1;
	private double maxSpeed = 0.05;
	private double lastForce = 0;
	private double currentSpeed = 0;

	public ForceWheelAnimator(String group, Wheel wheel) {
		super(group, 1, wheel);
	}
	@Override
	public void run(double frac) {
        if ( m_lasttime == -1 )
            m_lasttime = System.currentTimeMillis()-20;
        long time = System.currentTimeMillis();
        long timestep = Math.min(getMaxTimeStep(), time - m_lasttime);
        
        //don't care about time
        if (!getVisualization().items(m_group, m_predicate).hasNext()){
        	return;
        }
        double force = force();
        if (ratio<0 && force != 0) {
        	ratio = Math.abs(force/maxSpeed);
        }
        force /=ratio;
        if (force>maxSpeed && Math.abs(force-lastForce)>0.1) {
        	ratio = force/maxSpeed*ratio;
        	force = Math.signum(force)*maxSpeed;
        	System.out.println("increasing ratio to " +ratio);
        }
        currentSpeed *=0.5;
        currentSpeed +=force*0.5;//*(currentTime-lastTime)/100;
        setRadPerSec(currentSpeed/timestep*1000);
        setAngle(currentSpeed);//*(currentTime-lastTime)/100);
        Iterator<Tuple> it = wheel.keywordTable.tuples();
        while (it.hasNext()){
        	process(wheel.keywordItem(it.next()), 1);
        }
        wheel.updateStarLayers();
        lastForce = force;
	}
	private double force(){
		double torch = 0;
		for(EdgeItem edge : wheel.bridges()){
			torch = updateTorch(edge, wheel.center, torch);
		}
		return torch/wheel.radius;
	}
	private double updateTorch(EdgeItem edge, Point2D center, double oldTorch){
		int indi = indicator(edge, center);
		double dist = Geom.ptLineDist(edge, center);//asLine.ptLineDist(center);
		double length = Geom.length(edge);
		//return oldTorch + indi*dist*length/length;//springs have equal forces
		return oldTorch + indi*dist*length*springForce(edge);//springs have force proportional to their lengths
	}
	public double springForce(EdgeItem edge){
		return edge.getSize();
	}
	private int indicator(EdgeItem edge, Point2D center){
		int indi = Geom.relativePos(edge, center);//asLine.relativeCCW(center);
		if(edge.getSourceItem().getString(WheelDisplay.WHEEL).equals(wheel.name)){
			indi = 0 - indi;
		}
		else if(!edge.getTargetItem().getString(WheelDisplay.WHEEL).equals(wheel.name)){
			throw new IllegalStateException("should has one node on the wheel:"+wheel.name);
		}
		return indi;
	}
}